package com.hqyj.springBoot.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;


@Component//注册成为ioc的Bean
@Aspect//注册为切面程序
public class ControllerAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAspect.class);

    /**
     * 切入com.hqyj.springBoot_01.modules路径下的所有有controller层的包中的所有类中的所有方法并包含所有的参数和所有的返回值
     * 第一个 * 代表返回值可行不限
     * 第二个 * 代表modules下的所有自包
     * 第三个 * 代表controller层下的所有类
     * 第四个 * 代表类下的所有方法
     * .. 代表多有的参数
     * order代表 优先级，数字越小优先级越高
     */
    //AOP需求：在控制器中打印请求的相关信息，排除test模块的控制器；还要统计目标方法的执行时间
    @Pointcut("execution(public * com.hqyj.springBoot.modules.*.controller.*.*(..)) && " +
            "!execution(public * com.hqyj.springBoot.modules.common.controller.WebSocketController.*(..))")
    @Order(1)
    public void controllerPointCut(){}//代表的是控制器的切点

    @Pointcut("@annotation(com.hqyj.springBoot.aspect.MyAnnotation)")
    @Order(1)
    public void annotationPointcut(){}//代表注解的切点

    @Before(value = "controllerPointCut()")
    public void beforeController(JoinPoint joinPoint){
        //因为跟before注解冲突所以用上下文的方式获得request对象
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        LOGGER.debug(String.format("请求来源： %s", request.getRemoteAddr()));
        LOGGER.debug(String.format("请求路劲： %s", request.getRequestURI()));
        LOGGER.debug(String.format("请求方式： %s", request.getMethod()));
        LOGGER.debug(String.format("请求类： %s", joinPoint.getTarget().getClass().getName()));
        LOGGER.debug(String.format("请求方法： %s", joinPoint.getSignature().getName()));
        LOGGER.debug(String.format("请求参数： %s", joinPoint.getArgs() != null ? joinPoint.getArgs() : ""));
        LOGGER.debug("==== Before Controller Aspect ====");
    }

    @After(value = "controllerPointCut()")
    public void afterController(JoinPoint joinPoint){
        LOGGER.debug("==== After Controller Aspect ====");
    }

    @Around(value = "controllerPointCut()")
    public Object aroundController(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        LOGGER.debug("==== Around Controller Aspect ====");
        return proceedingJoinPoint.proceed();
    }

    @Around(value = "annotationPointcut()")
    public Object aroundAnnotation(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        LOGGER.debug("==== Aound annotation aspect ====");
        long start = System.currentTimeMillis();//获取刚开始执行这个方法时的系统时间的毫秒数
        Object object = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());//执行目标方法的方法体
        long end = System.currentTimeMillis();//获始执行完成这个方法时的系统时间的毫秒数
        LOGGER.debug(String.format("目标方法执行时间： %s", (end - start)));
        return object;
    }

}
